#! /usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2011 BidiX (http://bidix.info)
#
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.
#
"""
	defines Markdown extensions:
	
	- :class:`DelExtension`
	- :class:`HilitedExtension`
	- :class:`InlineExtension`
	- :class:`WikiLinkExtension`
"""
import re
import markdown
from markdown.util import etree
from markdown.inlinepatterns import Pattern

DEL_RE = r'(--)(.*?)--'

class DelExtension(markdown.Extension):
	"""
	DelExtension
	
	-- Text deleted -- is converted to <del>Text deleted</del>
	
	"""
	def extendMarkdown(self, md, md_globals):
		del_tag = markdown.inlinepatterns.SimpleTagPattern(DEL_RE, 'del')
		md.inlinePatterns.add('del', del_tag, '>not_strong')

HILITED_RE = r'(!!)(.*?)!!'

class SpanPattern (Pattern):
	# Return element of type `span` with a class `cls` with a text attribute of group(3)
	# of a Pattern.

	def __init__ (self, pattern, cls):
		Pattern.__init__(self, pattern)
		self.cls = cls

	def handleMatch(self, m):
		el = markdown.util.etree.Element('span')
		el.set('class', self.cls)
		el.text = m.group(3)
		return el



class HilitedExtension(markdown.Extension):
	"""
	HilitedExtension
	
	!!text hilited!! is converted to <span class="hilited">text hilited</span> 
	"""
	def extendMarkdown(self, md, md_globals):
		hilited_tag = SpanPattern(HILITED_RE, 'hilited')
		md.inlinePatterns.add('hilited', hilited_tag, '>not_strong')
	

LEFT_ARROW_PATTERN_RE = r'->'
LEFT_DOUBLE_ARROW_PATTERN_RE = r'=>'
RIGHT_ARROW_PATTERN_RE = r'<-'
RIGHT_DOUBLE_ARROW_PATTERN_RE = r'<='
COPYRIGHT_RE = r'\(c\)'
REGISTRED_RE = r'\(r\)'
HELLIP_RE = r'\.\.\.'
RAQUO_RE = r'>>'
LAQUO_RE = r'<<'
LEFT_TRIANGLE_RE = r'\(>\)'
DOWN_TRIANGLE_RE = r'\(v\)'

class SimpleTextPattern (Pattern):
	# Return a simple text of group(2) of a Pattern.
	def __init__ (self, pattern, replace):
		Pattern.__init__(self, pattern)
		self.replace = replace

	def handleMatch(self, m):
		return self.replace

class InlineExtension(markdown.Extension):
	"""
	InlineExtension
	convert characters to a symbol:

	========	========	
	 Chars. 	 Symbol 	
	========	========	
	  `->`  	  →  	
	  `=>`  	  ⇒  	
	  `<-`  	  ←  	
	  `<=`  	  ⇐  	
	  `(c)`  	  ©  	
	  `(r)`  	  ®  	
	  `...`  	  …  	
	  `<<`  	  «  	
	  `>>`  	  »  	
	  `(>)`  	  ▶  	
	  `(v)`  	  ▼  	
	========	========	
	
	"""
	def extendMarkdown(self, md, md_globals):
		md.inlinePatterns["left_arrow"] = \
			SimpleTextPattern(LEFT_ARROW_PATTERN_RE, u'→')
		md.inlinePatterns["left_double_arrow"] = \
			SimpleTextPattern(LEFT_DOUBLE_ARROW_PATTERN_RE, u'⇒')
		md.inlinePatterns["right_arrow"] = \
			SimpleTextPattern(RIGHT_ARROW_PATTERN_RE, u'←')
		md.inlinePatterns["right_double_arrow"] = \
			SimpleTextPattern(RIGHT_DOUBLE_ARROW_PATTERN_RE, u'⇐')
		md.inlinePatterns["copyright"] = \
			SimpleTextPattern(COPYRIGHT_RE, u'©')
		md.inlinePatterns["registred"] = \
			SimpleTextPattern(REGISTRED_RE, u'®')
		md.inlinePatterns["hellip"] = \
			SimpleTextPattern(HELLIP_RE, u'…')
		md.inlinePatterns["raquo"] = \
			SimpleTextPattern(RAQUO_RE, u'»')
		md.inlinePatterns["laquo"] = \
			SimpleTextPattern(LAQUO_RE, u'«')
		md.inlinePatterns["left_triangle"] = \
			SimpleTextPattern(LEFT_TRIANGLE_RE, u'\u25B6')
		md.inlinePatterns["down_triangle"] = \
			SimpleTextPattern(DOWN_TRIANGLE_RE, u'\u25BC')


def element_builder(label, anchor, title, base_url, end_url, context):
	""" 
	Build an 'a' element parameters.
	
	This function is provided as an example. A concrete usage of this WikiLink extension should 
	provide its own implementation.	
	
	Args:
		label (String): Optional the label part of the WikiLink
		anchor (String): Optional the anchor part of the WikiLink
		title (String): Optional Text part of the WikiLink
		base_url (String): From config
		end_url (String): from config
		context (Any): from config
	Returns:
		(url, text, title, url_exists)
	"""
	clean_label = re.sub(r'([ ]+_)|(_[ ]+)|([ ]+)', '_', label)
	url = '%s%s%s'% (base_url, clean_label+anchor, end_url)
	text = label+anchor
	if not title:
		title = clean_label+anchor
	url_exists = False
	return (url, text, title, url_exists)


class WikiLinkExtension(markdown.Extension):
	"""
	WikiLinkExtension
	
	Based on WikiLinks extension to Markdown
	http://www.freewisdom.org/projects/python-markdown/WikiLinks
	
	Syntax::
    		
    		[text[article_name#anchor]]
    	
    with	
		text (optional)
		:	replace the title of article as clickable texte
		
		article_name (optional)
		:    The [[notewiki/doc/definitions/name]] of the article or its `relative_article_name` 
		
		\#anchor (optional)
		:	insert #anchor to link. 
		
		relative_article_name
		:   The wikilink is relative to the current article depending of the sub-syntax for `relative_article_name`:  
		    * +/basename* : basename of article as sub-article of the current article  
		    * ./basename* : basename of article as sub-article of parent of the current article  
		    * ../basename* : basename of article as sub-article of parent of parent of current article  

	added from the Standard Markdown Extension:
	  - a missing_html_class used as class in the link if the build_text return exists=False
	  - a context object to pass global context
	  - elemnt_buider callback with more parameters see :func:`element_builder`
	
	Usage:
		exemple from Notewiki App::

			def wikilinks_element_builder(label, anchor, title, base_url, end_url, article):
				...
				 
			wikilink_extension_configs = [
									('base_url', base_url),
									('end_url', ''),
									('element_builder', wikilinks_element_builder),
									('context', article)
									]
			md = markdown.Markdown(
				extensions = [
					...
					md_extensions.WikiLinkExtension(wikilink_extension_configs),
					...
					])
					
			html = md.convert(text)
	
	"""
	def __init__(self, configs):
		# set extension defaults
		self.config = {
						'base_url' : ['/', 'String to append to beginning or URL.'],
						'end_url' : ['/', 'String to append to end of URL.'],
						'html_class' : ['wikilink', 'CSS hook. Leave blank for none.'],
						'missing_html_class' : ['missing-wikilink', 'CSS hook. Leave blank for none.'],
						'element_builder' : [element_builder, 'Callable formats URL from label.'],
 						'context' : [None, 'Global context available for building label.'],
		}
		
		# Override defaults with user settings
		for key, value in configs :
			self.setConfig(key, value)
		
	def extendMarkdown(self, md, md_globals):
		self.md = md
	
		# append to end of inline patterns
		# added '/' in wikilink 
		WIKILINK_RE = r'\[([^\[]*)\[([A-Za-z0-9_ .+\-/]+)?(#.*?)?\]\]'
		wikilinkPattern = WikiLink(WIKILINK_RE, self.config)
		wikilinkPattern.md = md
		md.inlinePatterns.add('wikilink2', wikilinkPattern, "<not_strong")


class WikiLink(markdown.inlinepatterns.Pattern):
	
	def __init__(self, pattern, config):
		markdown.inlinepatterns.Pattern.__init__(self, pattern)
		self.config = config
		
	def handleMatch(self, m):
		if m.group(3) or m.group(4):
			base_url, end_url, html_class, missing_html_class, context = self._getMeta()
			if m.group(3):
				label = m.group(3).strip()
			else:
				label = ''
			if m.group(2):
				title= m.group(2).strip()
			else:
				title=''
			if m.group(4):
				anchor= m.group(4).strip()
			else:
				anchor=''
			url, text, title, url_exists = self.config['element_builder'][0](label, anchor, title, base_url, end_url, context)
			a = markdown.util.etree.Element('a')
			a.set('href', url)
			a.text = text
			a.set('title', title)
			if url_exists and html_class:
				a.set('class', html_class)
			elif not url_exists and missing_html_class:
				a.set('class', missing_html_class)
		else:
			a = ''
		return a

	def _getMeta(self):
		""" Return meta data or config data. """
		base_url = self.config['base_url'][0]
		end_url = self.config['end_url'][0]
		html_class = self.config['html_class'][0]
		missing_html_class = self.config['missing_html_class'][0]
		context = self.config['context'][0]
		if hasattr(self.md, 'Meta'):
			if self.md.Meta.has_key('wiki_base_url'):
				base_url = self.md.Meta['wiki_base_url'][0]
			if self.md.Meta.has_key('wiki_end_url'):
				end_url = self.md.Meta['wiki_end_url'][0]
			if self.md.Meta.has_key('wiki_html_class'):
				html_class = self.md.Meta['wiki_html_class'][0]
			if self.md.Meta.has_key('wiki_missing_html_class'):
				html_class = self.md.Meta['wiki_missing_html_class'][0]
			if self.md.Meta.has_key('context'):
				context = self.md.Meta['context'][0]
		return base_url, end_url, html_class, missing_html_class, context
	
